const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const BundleAnalyzerPlugin =
	require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')

const smp = new SpeedMeasurePlugin()
const { srcPath, distPath } = require('./src/utils/paths')
const {
	Reg_js,
	Reg_css,
	Reg_less,
	Reg_image,
	Env_development,
	Env_production,
} = require('./src/utils/webpackConst')

const isProduction = Env_production === process.env.NODE_ENV
const styleLoader = isProduction ? MiniCssExtractPlugin.loader : 'style-loader'
console.log('process.env.Env_production', Env_production, process.env.NODE_ENV)

const config = {
	entry: {
		index: path.join(srcPath, 'index.js'),
	},
	devtool: 'source-map',
	module: {
		// 不解析浏览器可以运行的 ES5 代码
		noParse: /(react\.min\.js)|lodash/,
		rules: [
			{
				test: Reg_js,
				// cacheDirectory：默认值为 false。当有设置时，指定的目录将用来缓存 loader 的执行结果。之后的 webpack 构建，将会尝试读取缓存，来避免在每次执行时，可能产生的、高性能消耗的 Babel 重新编译过程(recompilation process)。
				// thread-loader 多进程打包
				// use: ['thread-loader', 'babel-loader?cacheDirectory'],
				use: ['babel-loader?cacheDirectory'],
			},
			{
				test: Reg_css,
				use: [styleLoader, 'css-loader', 'postcss-loader'],
			},
			{
				test: Reg_less,
				use: [
					styleLoader,
					'css-loader',
					'less-loader',
					'postcss-loader',
				],
			},
			// 打包 image 根据文件大小判断是否是 inline 模块类型或者是 resource 模块类型
			{
				test: Reg_image,
				type: 'asset',
				parser: {
					dataUrlCondition: {
						maxSize: 5 * 1024, // 5kb
					},
				},
				generator: {
					filename: 'static/[hash][ext][query]',
				},
			},
		],
	},
	plugins: [
		new BundleAnalyzerPlugin(),
		// 默认配置的具体配置项
		// new BundleAnalyzerPlugin({
		//   analyzerMode: 'server',
		//   analyzerHost: '127.0.0.1',
		//   analyzerPort: '8888',
		//   reportFilename: 'report.html',
		//   defaultSizes: 'parsed',
		//   openAnalyzer: true,
		//   generateStatsFile: false,
		//   statsFilename: 'stats.json',
		//   statsOptions: null,
		//   excludeAssets: null,
		//   logLevel: info
		// html 文件解析
		new HtmlWebpackPlugin({
			template: path.join(srcPath, 'tpl/index.html'),
			filename: 'index.html',
			chunks: ['index'],
		}),
		// 忽略 moment 下的 /locale 目录
		new webpack.IgnorePlugin({
			resourceRegExp: /^\.\/locale$/,
			contextRegExp: /moment/,
		}),
	],
}

if (isProduction) {
	config.mode = Env_production
	config.output = {
		path: distPath,
		filename: '[name].[contenthash].bundle.js',
		assetModuleFilename: 'assets/[hash][ext][query]',
		// publicPath: 'http://cdn.abc.com'  // 修改所有静态文件 url 的前缀（如 cdn 域名），这里暂时用不到
	}
	// 基于文件系统的持久化缓存无论在单独构建或连续构建(可以指热更新操作)中都可应用，首先它会查看内存缓存，如果未命中，则降级到文件系统缓存。
	config.cache = {
		type: 'filesystem',
		buildDependencies: {
			defaultWebpack: ['webpack/lib/'],
			config: [__filename],
		},
		name: `${process.env.NODE_ENV || ENV_production}-cache`,
	}
	config.optimization = {
		minimize: true,
		minimizer: [
			// 压缩 css
			new CssMinimizerPlugin(),
			// 默认配置 '...'
			new TerserPlugin({
				// 多进程压缩
				parallel: true,
			}),
		],
		// Webpack 5 新增了长期缓存算法，以确定性的方式为模块和分块分配短的(3 或 5 位)数字 ID，这是包大小和长期缓存之间的一种权衡，生产环境默认开启以下配置。在减小文件打包大小同时也利于浏览器长期缓存(不会因为删除或新增一个模块而导致大量缓存文件失效)。
		// moduleIds: 'deterministic',
		// chunkIds: 'deterministic',
		// mangleExports: 'deterministic',
		splitChunks: {
			// initial 入口chunk，对于异步导入的文件不处理
			// async 异步chunk，只对异步导入的文件处理
			// all 全部chunk
			chunks: 'all',
			// 缓存分组
			cacheGroups: {
				// 第三方模块
				vendor: {
					name: 'vendor',
					priority: 1,
					test: /node_modules/,
					minSize: 0,
					minChunks: 1, // 最少复用过1次
				},
				// 公共的模块
				common: {
					name: 'common',
					priority: 0,
					minSize: 0,
					minChunks: 2, // 公共模块最少复用2次
				},
			},
		},
	}
	const plugins = [
		// 清空 output.path 文件夹
		new CleanWebpackPlugin(),
		// 定义环境变量
		new webpack.DefinePlugin({
			// 必须传 json 数据。JSON.stringify(Env_development) | JSON.stringify('development') | '"development"'
			ENV: JSON.stringify(Env_production),
		}),
		// 抽离 css
		new MiniCssExtractPlugin(),
	]
	config.plugins = [...config.plugins, ...plugins]
} else {
	config.mode = Env_development
	config.cache = {
		type: 'memory',
	}
	config.devServer = {
		open: true,
		host: 'localhost',
		port: 8000,
		// 浏览器端显示进度
		client: {
			progress: true,
		},
		// 开启 gzip 压缩
		compress: true,
		// 启用 热更新
		hot: true,
		// 当在webserver中配置这一属性的时候，当后端路由没有命中（手动输入/detail），就会自动render index.html，这时候，react-router就会生效，detail页面就能出来啦。
		historyApiFallback: true,
		// 设置代理
		proxy: {
			// 将本地 /api/xxx 代理到 localhost:3000/api/xxx
			'/api': 'http://localhost:3000',
			// 将本地 /api2/xxx 代理到 localhost:3000/xxx
			'/api2': {
				target: 'http://localhost:3000',
				pathRewrite: {
					'/api2': '',
				},
			},
		},
	}
	const plugins = [
		// 定义环境变量
		new webpack.DefinePlugin({
			// 必须传 json 数据。JSON.stringify(Env_development) | JSON.stringify('development') | '"development"'
			ENV: JSON.stringify(Env_development),
		}),
		// Scope Hoisting  development 模式下需要配置，生产模式自动开启。功能是对作用域进行提升，并且让webpack打包后的代码更小、运行更快。插件是这个插件的应用范围是ES6语法的模块，如果是用的CMD/AMD等非ES6语法的话，这个没办法起到优化的作用
		new webpack.optimize.ModuleConcatenationPlugin(),
		// 热更新
		new webpack.HotModuleReplacementPlugin({}),
	]
	config.plugins = [...config.plugins, ...plugins]
}

module.exports = smp.wrap(config)
